接續昨天的文章,繼續來講剩下的原則 ~
子類別可以替換父類別,而不會影響程式架構;子類別可以執行父類別想做的事。以下範例中,Square 繼承 Rectangle,但保持矩形的行為。
// Liskov 替換原則
public class Rectangle
{
public virtual double Width { get; set; }
public virtual double Height { get; set; }
public double GetArea()
{
return Width * Height;
}
}
public class Square : Rectangle
{
private double side;
public Square(double side)
{
this.side = side;
}
public override double Width
{
get { return side; }
set { side = value; }
}
public override double Height
{
get { return side; }
set { side = value; }
}
}
避免將不相關的功能放到同一個介面中,應該將它們拆成多個專門的介面;簡單來說就是將不同功能分離至不同介面。以下範例中,我們將列印和儲存功能分離到不同介面。
// 介面隔離原則
public interface IPrintable
{
void Print();
}
public interface ISavable
{
void Save();
}
public class Report : IPrintable, ISavable
{
public void Print()
{
Console.WriteLine("Printing Report...");
}
public void Save()
{
Console.WriteLine("Saving Report...");
}
}
高階模組不應依賴低階模組,兩者都應依賴於抽象;避免父類別因為子類別改變而被迫改變。以下範例中,我們將依賴反轉,使 OrderProcessor 依賴於 IPaymentProcessor 介面,而不是具體的實作。
// 依賴反轉原則
public interface IPaymentProcessor
{
void ProcessPayment(double amount);
}
public class PayPalPaymentProcessor : IPaymentProcessor
{
public void ProcessPayment(double amount)
{
Console.WriteLine($"Processing PayPal payment of {amount}...");
}
}
public class CreditCardPaymentProcessor : IPaymentProcessor
{
public void ProcessPayment(double amount)
{
Console.WriteLine($"Processing credit card payment of {amount}...");
}
}
public class OrderProcessor
{
private IPaymentProcessor paymentProcessor;
public OrderProcessor(IPaymentProcessor paymentProcessor)
{
this.paymentProcessor = paymentProcessor;
}
public void ProcessOrder(double amount)
{
paymentProcessor.ProcessPayment(amount);
}
}
用以下的程式呼叫上述類別:
public class Program
{
public static void Main()
{
// Liskov 替換原則
Rectangle rect = new Rectangle { Width = 5, Height = 10 };
Square square = new Square(5);
Console.WriteLine($"Rectangle area: {rect.GetArea()}");
Console.WriteLine($"Square area: {square.GetArea()}");
// 介面隔離原則
Report report = new Report();
report.Print();
report.Save();
// 依賴反轉原則
IPaymentProcessor paymentProcessor = new PayPalPaymentProcessor();
OrderProcessor orderProcessor = new OrderProcessor(paymentProcessor);
orderProcessor.ProcessOrder(250.0);
}
}
以上原則幫助你在寫出有彈性的程式,而且減少重複修改的機會,或是變成義大利麵般的雜亂!